package com.hooker.plugins;

import android.content.Context;
import android.os.Build;

import com.hooker.common.ReflectA;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;



public class Assistant{

    private static Assistant mSingleton;
    public static Assistant getInstance(Context context) {
        if(mSingleton == null) {
            synchronized(Assistant.class) {
                if(mSingleton == null) {
                    mSingleton = new Assistant(context);
                }
            }
        }
        return mSingleton;
    }

    private Assistant(Context context) {
        _context = context.getApplicationContext();
    }

    public void destroyHook() {
        setActivityManagerHooker(null);
        setPowerManagerHooker(null);
        setKeyguardManagerHooker(null);
        setOnAudioManagerHooker(null);
    }

    public static class Handle {
        private boolean IsCancel = false;
    }

    public interface OnActivityManagerHooker {
        Object invokeMethod(Object host, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
    }

    public interface OnKeyguardManagerHooker {
        Object invokeMethod(Object host, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
    }

    public interface OnPowerManagerHooker {
        Object invokeMethod(Object host, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
    }

    public interface OnAudioManagerHooker {
        Object invokeMethod(Object host, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
    }


    private Object activityManagerProxy;
    private Object powerManagerProxy;
    private Object keyguardManagerProxy;
    private Object audioManagerProxy;
    private Object handlerCallback;

    private Context _context;

    private OnKeyguardManagerHooker mKeyguardManagerHooker;
    private OnPowerManagerHooker mPowerManagerHooker;
    private OnActivityManagerHooker mActivityManagerHooker;
    private OnAudioManagerHooker onAudioManagerHooker;

    public void setPowerManagerHooker(OnPowerManagerHooker powerManagerHooker) {
        mPowerManagerHooker = powerManagerHooker;
    }

    public void clearPowerManagerHooker() {
        mPowerManagerHooker = null;
    }

    public void setActivityManagerHooker(OnActivityManagerHooker activityManagerHooker) {
        mActivityManagerHooker = activityManagerHooker;
    }

    public void clearActivityManagerHooker() {
        mPowerManagerHooker = null;
    }

    public void setKeyguardManagerHooker(OnKeyguardManagerHooker keyguardManagerHooker) {
        mKeyguardManagerHooker = keyguardManagerHooker;
    }

    public void clearKeyguardManagerHooker() {
        mPowerManagerHooker = null;
    }

    public void addHookServiceName (String serviceName) {
        serviceSet.add(serviceName);
    }

    public void setOnAudioManagerHooker(OnAudioManagerHooker onAudioManagerHooker) {
        this.onAudioManagerHooker = onAudioManagerHooker;
    }

    public void clearAudioManagerHooker(Object audioManagerProxy) {
        this.onAudioManagerHooker = null;
    }

    private HashSet<String> serviceSet = new HashSet<>();

    public boolean hook() throws Exception {
        Class<?> ia = Class.forName("android.app.IActivityManager");
        if (ia == null) {
            return false;
        }
        if(Build.VERSION.SDK_INT >= 29){
            Class<?> ita = Class.forName("android.app.IActivityTaskManager");
            Object iamSingleton = ReflectA.get(Class.forName("android.app.ActivityTaskManager"), "IActivityTaskManagerSingleton");
            if (iamSingleton == null) {
                return false;
            }
            Object iamInstance = ReflectA.get(iamSingleton, "mInstance");
            if (iamInstance == null) {
                return false;
            }
            if (iamInstance != activityManagerProxy) {
                activityManagerProxy = getActivityManagerProxy(iamInstance, ita);
                ReflectA.set(iamSingleton, "mInstance", activityManagerProxy);
            }
            Object iamSingleton2 = ReflectA.get(Class.forName("android.app.ActivityManager"), "IActivityManagerSingleton");
            if (iamSingleton2 == null) {
                return false;
            }
            Object iamInstance2 = ReflectA.get(iamSingleton2, "mInstance");
            if (iamInstance2 == null) {
                return false;
            }
            if (iamInstance2 != activityManagerProxy) {
                activityManagerProxy = getActivityManagerProxy(iamInstance2, ia);
                ReflectA.set(iamSingleton2, "mInstance", activityManagerProxy);
            }
        } else if (Build.VERSION.SDK_INT >= 26) {
            Object iamSingleton = ReflectA.get(Class.forName("android.app.ActivityManager"), "IActivityManagerSingleton");
            if (iamSingleton == null) {
                return false;
            }
            Object iamInstance = ReflectA.get(iamSingleton, "mInstance");
            if (iamInstance == null) {
                return false;
            }
            if (iamInstance != activityManagerProxy) {
                activityManagerProxy = getActivityManagerProxy(iamInstance, ia);
                ReflectA.set(iamSingleton, "mInstance", activityManagerProxy);
            }
        } else {
            Object v = ReflectA.get("android.app.ActivityManagerNative", "gDefault");
            if (v == null) {
                return false;
            }
            if (v.getClass().isAssignableFrom(ia)) {
                if (v != activityManagerProxy) {
                    activityManagerProxy = getActivityManagerProxy(v, ia);
                    ReflectA.set("android.app.ActivityManagerNative", "gDefault", activityManagerProxy);
                }
            } else {
                Object m = ReflectA.get(v, "mInstance");
                if (m == null) {
                    return false;
                }
                if (m != activityManagerProxy) {
                    activityManagerProxy = getActivityManagerProxy(m, ia);
                    ReflectA.set(v, "mInstance", activityManagerProxy);
                }
            }
        }
        return true;
    }

    private Object getActivityManagerProxy(final Object host, Class<?> ia) {
        return Proxy.newProxyInstance(Assistant.class.getClassLoader(), new Class<?>[]{ia}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (mActivityManagerHooker != null) {
                    return mActivityManagerHooker.invokeMethod(host, method, args);
                }
                return method.invoke(host, args);
            }
        });
    }

}
